

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

//=============导入高阶组件区=============
//1导入高阶组件,公共部分
import {createPage, base, ajax, high, toast, promptBox, deepClone} from 'nc-lightapp-front';
//2导入高阶组件, UIExtend的部分
import {Utils} from './Utils';

import NCUploader from 'uap/common/components/NCUploader';  // 附件管理组件

//=============导入基础组件区=============
//1基础组件,公共部分
const {NCDiv, NCAffix, NCTabs, NCScrollElement} = base;
//2导入基础组件. UIExtend部分


//=============基本变量定义区=============
//1 基础常用变量声明部分
const EMPTY_FN = function(){}; //空函数

const URLS = {  // 请求路径
    loadUrl: '/nccloud/arap/HsbcEbankPay/LoadHsbcEbankPayVOAction.do'
};

const ACTIONS = {  // 按钮编码
    ATTACHMENT: 'Attachment',  //附件
    REFRESH: 'Refresh',  //刷新
}

const FIELDS = {  // 字段编码
    APPROVESTATUS : 'fstatusflag',
    BILLTYPE : 'pk_billtypecode',
    TRANSTYPEPK: 'ctranstypeid',
    TRANSTYPE: 'vtranstypecode',
    CODE: 'vbillcode',
    PRIMARYKEY: 'pk_extract'
}

//2 编辑模式变量
const EDITMODE_EDIT = 'edit';
const EDITMODE_BROWSE = 'browse';

//3 页面显示模式
//3.1 当前UIExtend需要定义的状态
const SHOWMODE_CARD = 'card';


const CARDTABLE_SUFFIX = '_sub';  //卡片表格区域编码后缀


/****************************************************************************************************
 * 整体介绍：
 *      目前的这种写法是 单页应用的写法，多页面应用，页面切换时，采用的是“安装-卸载”的方式体现在render方法
 *      目前的这种写法，我们不需要再关注this指针的问题,也不需要在调用方法时使用call来切换指针并执行，直接"方法()"即可
 *      目前的这种写法，采用的是MVVM的架构模式，把state看做是VM，所以我们需要把目光集中在state
 ****************************************************************************************************/

export class ApplicationPage extends Component{
	/**
	* 构造方法,js要求的必须方法,构造整个页面对象，
	* 此方法构造时，会定义全局配置，this.config,方便其他方法取用,
	* 同时，也处理了加载模板,按钮，设置模板按钮功能，最终通过调用
	* pageReady(此方法可以加入你的业务逻辑)完成第一次页面.
	* 此方法中,会调用initButton,initMeta来初始化模板和按钮,
	* initButton,initMeta,pageReady仅在页面打开时调用一次.
	* 其他时候不再调用
	*/
    constructor(props) {
        super(props); //构造
        
       // 节点全局变量定义
       //包含 页面编码定义,应用编码定义,标题定义,模块组件名定义
       //配置的获取方式，优先取平台定义,其次取传入配置定义, 最后默认
        this.config = {
            pagecode: props.getSearchParam('p')   || props.appcode || 'pagecode未定义', //页面编码定义
            appcode: props.getSearchParam('c')    || props.appcode || 'appcode未定义',  //应用编码定义
            title: this.props.getSearchParam('n') || props.title   || 'Demo主从表',     //表体定义
            moduleId: props.appcode,  //多语资源目录id
            domainName: 'arap' //模块域名
        }
        /**
         * 创建state,并构造节点模型,其结构与渲染时是一致的.
         * 可参照顶端代码注释的详细解释
         */
        this.state = this.createState();
        
         /**
         * 适配版本变化,2105及其以后版本必须的调用, 2之前版本不需要
         */
        this.props.use.form('HsbcEbankPayVO_form');
        this.props.use.cardTable('HsbcEbankPayDetailVO_sub');
        
        /**
         * 加载NCC资源,
         * 1,包含单据模板,按钮,等平台定义的功能
         * 2,加载多语资源文件,
         * 3,加载需要在代码总用到参照js
         */
        Utils.loadNCCResource({
            props: props,
            referObjs: [],
            /**
             * 导入全局配置,加载资源时 appcode,pagecode,modulename等信息,
             * 需要用到,全局配置中包含所有它需要用到的参数,
             */
            ...this.config,
            //导入全局配置,
            callback: (data) => {
                let {context, template, button, lang, refer = {}} = data;
                /**
                 * 初始化模板,修改模板相关配置
                 * 初始化按钮,修改按钮相关配置,
                 * 并将模板配置,按钮配置输入到平台,通过setMeta,setButtons输入.
                 * 让平台进行初始化.当平台初始化完成后,通过then继续后续的工作
                 */
                template = this.initMeta(template); //更新模板
                button = this.initButton(button);
                Promise.all([//合并处理 模板 和 多语
                    new Promise(resolve => this.props.meta.setMeta(template, () => resolve(true))),
                    new Promise(
                        resolve => this.props.button.setButtons(button, () => resolve(true)))
                ]).then(() => {
                    this.setState({isPageReady: true}, () => {  //标记自己页面已经完成,并进行第一次的渲染
                        (this.pageReady || EMPTY_FN)();
                    });
                }).catch((e) => {
                    throw new ReferenceError(e);
                });
            }
        });
    }
    
    /**
     * pageReady方法为页面已经完全设置完毕，
     * 可以初始化一些初始的功能，比如查询下列表并显示数据等
     */
    pageReady = () => {
    	let scene = this.props.getUrlParam("scene");
        let id = this.props.getUrlParam("id");
        let status = this.props.getUrlParam("status");
        let allpks = id instanceof Array ? id:[id];
        if(!id){
        	toast({content: "系统错误，未传递联查pk！", color: 'danger'});
        	return;
        }
        this.state.allpks = allpks;
        this.state.currentId = allpks[0];
        this.setState(this.state, () =>  this.browseCard(this.state.currentId));
    }
    
    /**
      * 初始化平台定义的单据模板
      * 触发时机：执行loadNCCResource,加载完模板、多语、等初始化信息之后触发
      * 功能：对加载完的模板进行个性化调整
      * 可实现举例功能:
      * 1.参照表单联动过滤, 参见[Demo1] 
      * 2.处理表格操作列,   参见[Demo2]
      */
    initMeta = (meta) => {
        // 交易类型参照过滤
        meta['HsbcEbankPayVO_form'].items.find(item => item.attrcode == FIELDS.TRANSTYPEPK).queryCondition = () => ({
            parentbilltype: BILLTYPE
        });
        /**
         * Demo[1]参照过滤
         * 场景描述： 表单上同时有部门、组织两个字段，部门受组织过滤, 部门选择时,受到选择的组织进行部门参照过滤
         * 达成效果： 组织不选时，部门加载全部；组织选择，部门加载的数据时该组织下的部门。
         * 写法解释： 见下面代码注释,
         * 代码示例:
         */
        // meta['MasterVO_form'].items.find(item => item.attrcode == 'pk_dept').queryCondition = () => {
        //     let pk_group = this.props.form.getFormItemsValue(this.state.card.form.id, 'pk_group'); // 获取表单字段值
        //     let pk_org = this.props.form.getFormItemsValue(this.state.card.form.id, 'pk_org');
        //     return {
        //         pk_group: pk_group || '',
        //         pk_org: pk_org || ''
        //     };
        // };
        /**
         * Demo[2]处理表格操作列
         * 场景描述： 高阶组件simpleTable或者cardTable需要追加操作列
         * 达成效果： simpleTable或者cardTable,增加操作列,操作列中包含一些定义的按钮
         * 写法解释： 见代码注释
         * 代码示例:
         */
        // meta['MasterVO_list'].items.push({
        //     attrcode: 'opr', // 列标识, 固定
        //     itemtype:'customer', // 列类型, 固定
        //     label: '操作', // 列名
        //     width: 200, // 列宽度
        //     className : 'table-opr', // 样式
        //     fixed: 'right', // 悬浮方向
        //     visible: true, // 是否可见
        //     render: (text, record, index) => { // 渲染方法
        //         let oprButtons = [ACTIONS.EDIT, ACTIONS.DELETE];
        //         return this.props.button.createOprationButton(oprButtons, { // 调用表肩按钮创建API
        //             area: 'common',
        //             buttonLimit: 3,
        //             onButtonClick: (props, btncode) => this.onHeadBtnClick(props, btncode, {record, index})
        //         });
        //     }
        // });
        return meta;
    }
    /**
     * initButton方法 功能介绍：
     * 触发时机：执行loadNCCResource,加载完模板、多语、等初始化信息之后触发
     * 功能简介：对加载完的按钮数据进行个性化调整
     * 举例功能：
     * 1、禁用某按钮 参见Demo1
     */
    initButton = (button) => {
        /**
         * Demo1 处理按钮
         * 场景描述： 有时需要在按钮数据加载之后进行一些处理
         * 达成效果： 按钮不可见，并且禁用
         * 写法解释： 迭代所有按钮，找到Save按钮，设置按钮的可见性和禁用型
         * 代码示例:
         */
        //buttons.find(btn=>{//迭代buttons
        //  if(btn.key == 'Save'){//找到button的key为Save的按钮
        //      btn.disabled = true;//设置按钮禁用
        //      btn.visible = false;//设置按钮隐藏
        //  }
        //})
        return button;
    }
    /**
     * 创建state模型
     * state的模型结构于页面结构是一致的.请优先阅读开头的说明 3.2 createState方法，render方法
     * state中得必有并且常用得属性
     * isPageReady: 页面是否可以进行渲染，构造函数会异步请求模板,所以构造函数执行完成后,
     *              React在构造函数执行完后会立即调用render方法渲染页面,此时可能模板还没有加载完成,
     *              所以通过此属来标记模板等初始化数据是否加载完成. 加载完成后,isPageReady=true.
     *              才开始正式得渲染页面，参考render方法这种对isPageReady的使用。
     * showmode：   页面当前的显示模型,SHOWMODE为前缀的常量定义,你的应用有几个页面的,就有几个SHOWMODE的常量定义
     *              分别对应不同页面,比如，主从页面中(不带插件), 有列表和卡片两个页面, 则会使用到SHOWMODE_LIST
     *              SHOWMODE_CARD, render方法的中根据showmode值,来具体渲染页面.
     * editmode:    页面当前编辑模式,有两种状态, EDITMODE为前传的常量定义， EDITMODE_BROWSE,EDITMODE_EDIT;
     *              高阶组件的中的编辑状态与它保持一致的。当设置或改变editmode时,高阶组件的状态也要随之变化,
     *              如form formlist.
     * 模型结构定义说明： 建议优先阅读开头的说明3.2 createState方法，render方法
     * 这块基本模型，含义，表示是什么，起什么作用：参考3.2 create方法， 但是要结合你的模型
     * 主子表
     *	head: {  // 节点标题栏
     *		title: this.config.title, // 标题
     *		initShowBackBtn: false, // 是否显示返回按钮
     *		backBtnClick: this.onBackCard // 点击返回按钮
     *	},
     *	headBtn: { // 头部按钮区
     *		area: 'common', // 区域编码
     *		onButtonClick: this.onBtnClickHead // 点击按钮
     *	},
     *	list: { // 列表页面
     *		search: { // 查询区
     *			area: 'MasterVO_query', // 区域编码
     *			clickSearchBtn: this.onSearchList // 点击查询按钮
     *		},
     *		table: { // 主表表格
     *			allpks: [], // 列表查询结果行pk数组
     *			area: 'MasterVO_list', // 区域编码
     *			showCheck: true, // 是否显示多选框
     *			showIndex: true, // 是否显示行序号
     *			adaptionHeight: false, // 是否自适应浏览器高度
     *			onRowClick: this.onRowClickTable, // 点击行
     *			onRowDoubleClick: this.onRowDoubleClickTable, // 双击行
     *			handlePageInfoChange: (props, config, pks, total) => { // 表格分页信息改变及点击翻页按钮
     *				this.queryList({ // 查询列表
     *					callback: data => this.afterLoadList({data}) // 执行列表查询后逻辑
     *				});
     *			},
     *			selectedChange: this.onListSelectRowsChanged, // 选择框的选中行改变
     *			onSelectedAll: this.onListSelectRowsChanged, // 点击全选框
     *			onSelected: this.onListSelectRowsChanged // 点击选择框
     *		},
     *		tablelist: { // 列表子表详情
     *			tablelistRow: {}, // 列表子表明细对应主表行数据，只有当点击主表表格行时才会给这个属性设值，重新查询列表会清空 格式：{values: {}}
     *			activeKey: 'ChildVO_list', // 当前显示页签
     *			onChange: this.onTabChangedTablelist, // 选中页签改变
     *			onTabClick: EMPTY_FN, // 点击页签
     *			tablePanes: { // 页签信息
     *				'ChildVO_list'//区域编码//: {
     *					key: 'ChildVO_list', // 页签唯一标识
     *					tab: '子实体', // 页签显示名称
     *					table: { // 子表表格
     *						area: 'ChildVO_list', // 区域编码
     *						showIndex: true, // 是否显示行序号
     *						showCheck: false, // 是否显示多选框
     *						adaptionHeight: true, // 是否自适应浏览器高度
     *						handlePageInfoChange: (props, config, pks, total) => { // 表格分页信息改变及点击翻页按钮
     *							let {tablelistRow} = this.state.list.tablelist; // 获取子表详情对应主表行数据
     *							if (!(tablelistRow && tablelistRow.values)) { // 不存在对于主表行数据
     *								return;
     *							}
     *							this.querySubs({ // 查询子表
     *								callback: data => this.fillTablelistData({data}) // 填充数据
     *							});
     *						}
     *					}
     *				},
     *			}
     *		}
     *	},
     *	card: { // 卡片页面
     *		form: { // 表单
     *			area: 'MasterVO_form', // 区域编码
     *			onBeforeEvent: this.onBeforeEditForm, // 编辑前事件
     *			onAfterEvent: this.onAfterEditForm, // 编辑后事件
     *		},
     *		formlist: { // 子表表格
     *			'ChildVO_sub'//区域编码//: {
     *				area: 'ChildVO_sub', // 区域编码
     *				showIndex: true, // 是否显示行序号
     *				showCheck: true, // 是否显示多选框
     *				adaptionHeight: true, // 是否自适应浏览器高度
     *				onAfterEvent: this.onAfterEditFormlist, // 编辑后事件
     *				onBeforeEvent: this.onBeforeEditFormlist, // 编辑前事件
     *				onSelected: this.onSelectedChangeFormlist, // 点击选择框
     *				onSelectedAll: this.onSelectedChangeFormlist, // 点击全选框
     *				selectedChange: this.onSelectedChangeFormlist, // 选择框的选中行改变
     *				tableHead: () => this.state.card.formlist['ChildVO_sub'].button.render(), // 肩部渲染，主要用于渲染肩部操作按钮，调用肩部按钮的渲染方法
     *				button: { // 肩部按钮
     *					area: 'ChildVO', // 区域编码
     *					onButtonClick: (props, btnCode) => this.onBtnClickFormlist(props, btnCode, 'ChildVO_sub'), // 点击按钮
     *					render: () => { // 渲染方法
     *						return (
     *							<div className="shoulder-definition-area">
     *								<div className="btn-group">
     *									{//按钮//}
     *									{this.props.button.createButtonApp(this.state.card.formlist['ChildVO_sub'].button)}
     *								</div>
     *							</div>
     *						);
     *					}
     *				}
     *			}
     *		},
     *		cardPagniation: { // 翻页组件
     *			visible: false, // 是否显示
     *			handlePageInfoChange: this.onBtnClickCardPagniation // 点击翻页器按钮
     *		}
     *	}
     *
     * 其他功能是如何在state中定义
     * 特性模型的加入通过，Utils.apply方法蒋其他模型(插件模型加入到state中)
     * 可参见此方法中的具体的Utils.apply的注释
     * 例子：
     * state = { //基本模型
     *      list:{} 
     *      card:{}
     * }
     * uploader: { //上传组件
     *      visible: false, 
     *      billId: '',
     *      onHide: this.onHideUploader
     * }
     * 通过调用Utils.apply方法 Utils.apply(state, uploader);
     * 体现的结果为:
     * state = { //基本模型
     *      list:{} 
     *      card:{}
     *      uploader: { //上传组件
     *          visible: false, 
     *          billId: '',
     *          onHide: this.onHideUploader
     *      }
     * }
     */
    createState = () => {
        let state = {
        	scene : 'link',
        	currentId : '',
        	allpks : [],//所有联查的pk
            isPageReady: false, // 页面是否可以渲染
            showmode: SHOWMODE_CARD, // 页面当前的显示模型
            editmode: EDITMODE_BROWSE, // 页面当前编辑模式
            head: {  // 节点标题栏
                title: this.config.title, // 标题
                initShowBackBtn: false, // 是否显示返回按钮 
            },
            headBtn: { // 头部按钮区
                area: 'common', // 区域编码
                onButtonClick: this.onBtnClickHead // 点击按钮
            },
            card: { // 卡片页面
                form: { // 表单
                    area: 'HsbcEbankPayVO_form', // 区域编码
                    onBeforeEvent: this.onBeforeEditForm, // 编辑前事件
                    onAfterEvent: this.onAfterEditForm, // 编辑后事件
                },
                formlist: { // 子表表格
                    'HsbcEbankPayDetailVO_sub'/*区域编码*/: {
                        area: 'HsbcEbankPayDetailVO_sub', // 区域编码
                        showIndex: true, // 是否显示行序号
                        showCheck: true, // 是否显示多选框
                        adaptionHeight: true, // 是否自适应浏览器高度
                        onAfterEvent: this.onAfterEditFormlist, // 编辑后事件
                        onBeforeEvent: this.onBeforeEditFormlist, // 编辑前事件
                        onSelected: this.onSelectedChangeFormlist, // 点击选择框
                        onSelectedAll: this.onSelectedChangeFormlist, // 点击全选框
                        selectedChange: this.onSelectedChangeFormlist, // 选择框的选中行改变
                        tableHead: () => this.state.card.formlist['HsbcEbankPayDetailVO_sub'].button.render(), // 肩部渲染，主要用于渲染肩部操作按钮，调用肩部按钮的渲染方法
                        button: { // 肩部按钮
                            area: 'HsbcEbankPayDetailVO', // 区域编码
                            onButtonClick: (props, btnCode) => this.onBtnClickFormlist(props, btnCode, 'HsbcEbankPayDetailVO_sub'), // 点击按钮
                            render: () => { // 渲染方法
                                return (
                                    <div className="shoulder-definition-area">
                                        <div className="btn-group">
                                            {/*按钮*/}
                                            {this.props.button.createButtonApp(this.state.card.formlist['HsbcEbankPayDetailVO_sub'].button)}
                                        </div>
                                    </div>
                                );
                            }
                        }
                    }
                },
                cardPagniation: { // 翻页组件
                    visible: false, // 是否显示
                    handlePageInfoChange: this.onBtnClickCardPagniation // 点击翻页器按钮
                }
            }
        };
        
        // 附件管理
        Utils.apply(state, {
            uploader: { // 附件管理配置
                visible: false, // 是否可见
                billId: undefined, // 选中单据id
                onHide: this.onHideUploader, // 关闭附件管理回调
            }
        });
		
        return state;
    }
    //4 渲染方法
    render() {
        let {isPageReady, showmode, head, headBtn, list, card} = this.state;
        if(!isPageReady) return ''; //页面资源加载完成后才能渲染页面
    	// 渲染卡片
        const renderCardPage = () => {
            let {form, formlist, cardPagniation} = card;
            return showmode == SHOWMODE_CARD ? (
                <div className='nc-bill-extCard'>
                    <div className="nc-bill-top-area">
                        <NCAffix>
                            <NCDiv areaCode={NCDiv.config.HEADER} className='nc-bill-header-area'>
                            	<NCDiv areaCode={NCDiv.config.Title} className='header-title-search-area'>
                                    {this.props.BillHeadInfo.createBillHeadInfo(head)}
                                </NCDiv>
                                <div className="header-button-area">
                                    {this.props.button.createButtonApp(headBtn)}
                                </div>
                                <NCDiv areaCode={NCDiv.config.TABS} className='header-cardPagination-area' style={cardPagniation.visible ? {} : {display: 'none'}}>
                                    {this.props.cardPagination.createCardPagination(cardPagniation)}
                                </NCDiv>
                            </NCDiv>
                        </NCAffix>
                        <NCDiv areaCode={NCDiv.config.FORM} className="nc-bill-form-area">
                            <NCScrollElement name={form.area}>
                                {this.props.form.createForm(form.area, form)}
                            </NCScrollElement>
                        </NCDiv>
                    </div>
                    <div className="nc-bill-bottom-area">
                        {
                            (Object.values(formlist) || []).map(cfg => {
                                return (
                                    <NCDiv areaCode={NCDiv.config.TABLE} className="nc-bill-table-area">
                                        <NCScrollElement name={cfg.area}>
                                            {this.props.cardTable.createCardTable(cfg.area, cfg)}
                                        </NCScrollElement>
                                    </NCDiv>
                                );
                            })
                        }
                    </div>
                </div>
            ) : '';
        };
        
        // 附件组件
        const renderUploader = () => {
            let {uploader,uploader:{visible}} = this.state;
            return  visible ? (
                <NCUploader {...uploader}/>
            ) : '';
        }
        
      	return [ renderCardPage(),renderUploader() ];
      
      }//render
    
    //=============功能性方法区=============
    // 修改按钮状态
    // callback  回调
    updateBtnStatus = ({callback = EMPTY_FN} = {}) => {
        let {showmode, editmode} = this.state;
        let isBrowse = editmode == EDITMODE_BROWSE;

        // 按钮可见性初始化
        let btnVisible = {
            [ACTIONS.EDIT]: isBrowse,
            [ACTIONS.REFRESH]: isBrowse,
            [ACTIONS.SAVE]: !isBrowse,
            [ACTIONS.CANCEL]: !isBrowse
        }

        let btnDisabled = { 
            [ACTIONS.EDIT]: false,
            [ACTIONS.REFRESH]: false,
            [ACTIONS.SAVE]: false,
            [ACTIONS.SAVEADD]: false,
            [ACTIONS.CANCEL]: false
        }
        
		// 附件按钮控制
		Object.assign(btnVisible, {
			[ACTIONS.ATTACHMENT]: isBrowse
		});
		Object.assign(btnDisabled, {
            [ACTIONS.ATTACHMENT]: !this.state.currentId
		});

        let formlistBtn = (this.props.button.getButtons() || [])
                .filter(btn => btn.key.endsWith('_AddLine') || btn.key.endsWith('_DelLine'));
        // 卡片子表按钮可见性
        formlistBtn.forEach(btn => btnVisible[btn.key] = !isBrowse);
		// 卡片子表按钮可用性
		formlistBtn.forEach(btn => {
		    if (btn.key.endsWith('_DelLine')) { // 卡片子表是否选中行判断删行按钮是否可用
		        let cardTableCheckedRows = this.props.cardTable.getCheckedRows(btn.area + CARDTABLE_SUFFIX);
                btnDisabled[btn.key] = !(cardTableCheckedRows && cardTableCheckedRows.length > 0);
            } else {
                btnDisabled[btn.key] = false;
            }
        });

		// 附件按钮控制
		Object.assign(btnVisible, {
			[ACTIONS.ATTACHMENT]: isBrowse
		});
		Object.assign(btnDisabled, {
            [ACTIONS.ATTACHMENT]: false
		});
		
		this.props.button.setButtonVisible(btnVisible);
        this.props.button.setButtonDisabled(btnDisabled);
		// 设置卡片翻页器是否可见
        this.state.card.cardPagniation.visible =  editmode == EDITMODE_BROWSE;
        this.setState(this.state, callback);
    }
    
    // 查询卡片数据
    // data  查询参数
    // callback  回调
    queryCard = ({data, callback = EMPTY_FN} = {}) => {
        ajax({
            url: URLS.loadUrl,
            data: data,
            success: (res) => {
                let {data: {data} = {}} = res;
                callback(data);
            },
        });
    }

    // 填充卡片数据
    // data  billCard格式数据
    fillCardData = ({data} = {}) => {
        // 获取卡片区域编码
        let area = this.getCardAreaCode();
        // 设置主表单数据
        this.props.form.setFormItemsValue(area.formId, data && data.head && data.head[area.formId] && data.head[area.formId].rows[0].values || {});
        // 设置子表表格数据
        area.tableId.forEach(id => {
            if (data && data.bodys && data.bodys[id]) {
                this.props.cardTable.setTableData(id, data.bodys[id]);
            } else { // 子表没值则清空
                this.props.cardTable.setTableData(id, {rows: []});
            }
        });
    }

    // 清空卡片数据
    clearCardData = () => {
        // 获取卡片区域编码
        let area = this.getCardAreaCode();
        // 清空主表单数据
        this.props.form.EmptyAllFormValue(area.formId);
        // 清空子表表格数据
        area.tableId.forEach(id => {
            this.props.cardTable.setTableData(id, {rows: []});
        });
    }
    
    browseCard = (id) => {
        // 获取卡片区域编码
        let area = this.getCardAreaCode();

        // 调用卡片查询
        this.queryCard({
            data: { // 查询参数
                pageCode: this.config.pagecode, // pagecode
                pk: id, // 主键
                ...area // 卡片区域编码
            },
            callback: (data) => {
                this.fillCardData({data});
                // 根据列表数据初始化卡片翻页器
                this.initCardPaginationWithAllpks();
                // 设置翻页器当前的数据主键
                this.props.cardPagination.setCardPaginationId({id, status: 1});
                // 更新按钮状态
                this.updateBtnStatus();
            }
        });  
    }

    // 初始化卡片翻页器
    initCardPaginationWithAllpks = () => {
        let {allpks} = this.state.allpks;
        // 设置卡片翻页器的allpks，当调用cardPagination组件的API新增、删除pk时，allpks会同步更新
        this.props.cardPagination.setCardPaginationAllpks(allpks);
    }

    // 获取卡片数据
    getCardData = () => {
        // 获取卡片区域编码
        let area = this.getCardAreaCode();
        // 获取卡片界面数据（主表单、子表表格）
        let cardData = this.props.createExtCardData(this.config.pagecode, area.formId, area.tableId);
        
        return cardData;
    }

    // 获取卡片区域编码，包括主表单（formId）子表格（tableId），单表时没有tableId
    // 返回格式：{{formId: '', tableId: ['']}}
    getCardAreaCode = () => {
        return {
            tableId: Object.keys(this.state.card.formlist),
            formId: this.state.card.form.area
        }
    }
    
    
    /**
     * 按钮点击事件
     * @param props
     * @param btnCode  按钮id
     * @param param  列表操作列参数，适配操作列按钮
     */
    onBtnClickHead = (props, btnCode, param = {}) => {
        switch (btnCode) {
            case ACTIONS.EDIT: // 点击修改
                this.onEdit(param);
                break;
            case ACTIONS.REFRESH: // 点击刷新
                this.onRefresh();
                break;
            case ACTIONS.SAVE: // 点击保存
                this.onSave();
                break;
            case ACTIONS.CANCEL: // 点击取消
                this.onCancel();
                break;
            
            case ACTIONS.ATTACHMENT: // 点击附件管理
                this.onAttachment();
                break;
            default:
                break;
        }
    }
    
    /**
     * 点击刷新按钮
     */
    onRefresh = () => {
        
        // 获取主键
        let billId = this.state.currentId;
        // 获取卡片区域编码
        let area = this.getCardAreaCode();
        // 调用卡片查询
        this.queryCard({
            data: {
                pageCode: this.config.pagecode, // pagecode
                pk: billId, // 主键
                ...area // 区域编码
            },
            callback: (data) => {
                // 填充卡片数据或清空卡片数据
                data ? this.fillCardData({data}) : this.clearCardData();
                // 更新按钮状态
                this.updateBtnStatus();
                // 提示
                toast({color: 'success', content: '刷新成功'});
            }
        });
    }
    
    /**
     * 点击修改按钮
     */
    onEdit = (param = {}) => {
        let {showmode} = this.state;
        this.state.editmode = EDITMODE_EDIT;
        
        this.setState(this.state, () => {
            // 获取卡片区域编码
            let area = this.getCardAreaCode();
            // 设置卡片主表单为编辑态
            this.props.form.setFormStatus(area.formId, EDITMODE_EDIT);
            // 设置卡片子表表格为编辑态
            area.tableId.forEach(id => {
                this.props.cardTable.setStatus(id, EDITMODE_EDIT);
            });
            // 更新按钮状态
            this.updateBtnStatus();
        });
    }
    
    /**
     * 点击保存按钮
     */
    onSave = (param = {}, callback = EMPTY_FN) => {
        // 获取卡片区域编码
        let area = this.getCardAreaCode();
        // 卡片主表单必输项校验
        if (!this.props.form.isCheckNow(area.formId)) return;
        // 卡片子表必输项校验
        if (!this.props.cardTable.checkTableRequired(area.tableId)) return;
        // 获取卡片填写数据
        let saveData = this.getCardData();
        // 校验公式参数
        let areainfo = {
            [area.formId]: 'form'
        };
        area.tableId.forEach(areacode => {areainfo[areacode] = 'editTable'});
        // 保存前执行校验公式
        this.props.validateToSave(saveData, () => {
            // 保存请求
            ajax({
                url: URLS.saveUrl,
                data: {
                    billCard: saveData, // 卡片数据
                    pageCode: this.config.pagecode, // pagecode
                    ...area // 区域编码
                },
                success: (res) => {
                    let {data: {data} = {}} = res;
                    let {showmode} = this.state;
                    // 设置编辑模式为编辑态，不需要切换页面模式
                    this.state.editmode = EDITMODE_BROWSE;
                    this.setState(this.state, () => {
                        // 设置卡片主表单为浏览态
                        this.props.form.setFormStatus(area.formId, EDITMODE_BROWSE);
                        // 设置子表表格为浏览态
                        area.tableId.forEach(id => {
                            this.props.cardTable.setStatus(id, EDITMODE_BROWSE);
                        });
                        // 填充卡片数据或清空卡片数据
                        data ? this.fillCardData({data}) : this.clearCardData();
                        // 更新按钮状态
                        this.updateBtnStatus();
                        // 获取保存后数据主键
                        let billId = data.head[area.formId].rows[0].values[FIELDS.PRIMARYKEY].value;
                        // 设置卡片翻页器当前主键，status（1为修改，2为新增，3为删除）
                        this.props.cardPagination.setCardPaginationId(
                            {id: billId, status: 1});
                        // 提示
                        toast({color: 'success', content: '保存成功'});
                        callback(data);
                    });
                }
            });
        }, areainfo, 'extcard');
    }
    /**
     * 点击取消按钮
     */
    onCancel = () => {
        promptBox({
            color:'warning', // 弹框类型（success、info、warning、danger）
            title: '取消', // 标题
            content: '是否确认要取消？', // 提示内容
            beSureBtnName: '确定', // 确定按钮显示内容
            cancelBtnName: '取消', // 取消按钮显示内容
            beSureBtnClick : () => { // 点击确定按钮
                this.state.editmode = EDITMODE_BROWSE;
                this.setState(this.state, () => {
                    // 获取卡片区域编码
                    let area = this.getCardAreaCode();
                    // 设置卡片主表单为浏览态
                    this.props.form.setFormStatus(area.formId, EDITMODE_BROWSE);
                    // 设置卡片子表表格为浏览态
                    area.tableId.forEach(id => {
                        this.props.cardTable.setStatus(id, EDITMODE_BROWSE);
                    });
                    this.browseCard(this.state.currentId);
                });
            }
        })
    }
    
    
    /**
     * 卡片翻页
     * @param props
     * @param nextId  下一个单据id
     */
    onBtnClickCardPagniation = (props, nextId) => {
        this.setState({currentId:nextId},this.browseCard(nextId));
    }
    
    /**
     * 附件管理
     */
    onAttachment = () => {
        // 获取主键，选中多行取第一行
        let billId = this.state.currentId;
        // 设置显示附件管理组件
        this.state.uploader.visible = true;
        // 设置附件管理组件的主键
        this.state.uploader.billId = billId;
        this.setState(this.state);
    }
    /**
     * 隐藏附件管理
     */
    onHideUploader = () => {
        // 设置不显示附件管理
        this.state.uploader.visible = false;
        this.setState(this.state);
    }
    
    /**
     * 卡片子表编辑前事件
     */
    onAfterEditFormlist = () => {}

    /**
     * 卡片子表编辑后事件
     */
    onBeforeEditFormlist = () => {}

    /**
     * 卡片子表选择框发生改变事件
     */
    onSelectedChangeFormlist = () => {
        // 更新按钮状态
        this.updateBtnStatus();
    }

    /**
     * 卡片子表表肩按钮事件
     * @param props
     * @param btnCode  按钮id
     * @param tableId  表格id
     */
    onBtnClickFormlist = (props, btnCode, tableId) => {
        // 卡片子表表肩符合以_AddLine结尾的规范，根据后缀判断时什么按钮
        let code = btnCode.split('_');
        switch (code[code.length - 1]) {
            case 'AddLine': // 点击增行
                this.onCardTableAddLine(tableId);
                break;
            case 'DelLine': // 点击删行
                this.onCardTableDelLine(tableId);
                break;
            default:
                break;
        }
    }

    /**
     * 卡片子表增行
     * @param tableId  表格id
     */
    onCardTableAddLine = (tableId) => {
        // 对应卡片子表表格新增空行，可以在这里新增时设置子表默认值
        this.props.cardTable.addRow(tableId, -1, {}, true);
    }

    /**
     * 卡片子表删行
     * @param tableId  表格id
     */
    onCardTableDelLine = (tableId) => {
        // 获取卡片子表表格选中行
        let checkedRows = this.props.cardTable.getCheckedRows(tableId);
        // 遍历得到选中行下标数组
        let delIndex = checkedRows ? checkedRows.map(row => row.index) : [];
        // 删除卡片子表表格行
        delIndex && delIndex.length > 0 && this.props.cardTable.delRowsByIndex(tableId, delIndex);
    }
    
}

const config = {
    title: '网银支付联查',
    pagecode: '200804HSBCL_HsbcEbankPayVOL',
    appcode: '200804HSBCL',
    domainName: 'arap',
    version: 2111
};
ApplicationPage = createPage({
    initTemplate:{},
    billinfo: {
        billtype: 'extcard',
        pagecode: '200804HSBCL_HsbcEbankPayVOL',
        headcode: 'HsbcEbankPayVO_form',
        bodycode: ['HsbcEbankPayDetailVO_sub']
    }
})(ApplicationPage);

ReactDOM.render(<ApplicationPage {...config}/>, document.querySelector("#app"));

